using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
using NSMBe4;
using System.IO;
using ZiadSpace.Util;
using System.Collections;

namespace MKDS_Course_Editor.NSBTX
{
    public partial class nsbtx_ : Form
    {
        BackgroundWorker bwr = null;
        public string file_ = "";
        public bool nsbtp_ = false;
        public int timer = 0;
        public NSBTX_File nsbtx;
        System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(nsbtx_));
        public nsbtx_(string file, bool nsbtp)
        {
            file_ = file;
            nsbtp_ = nsbtp;
            InitializeComponent();
        }
        public void load()
        {
            if (nsbtp_ == true)
            {
                toolStripButton3.Enabled = true;
                toolStripButton6.Enabled = true;
                toolStripButton4.Enabled = true;
                toolStripButton8.Enabled = true;
            }
            /*NSMBe4.DSFileSystem.ExternalFilesystemSource f = new NSMBe4.DSFileSystem.ExternalFilesystemSource(file_);
            NSMBe4.DSFileSystem.Filesystem fs = new NSMBe4.DSFileSystem.Filesystem(f);
            NSMBe4.NSBMD.NSBTX nsbtx = new NSMBe4.NSBMD.NSBTX(new NSMBe4.DSFileSystem.File(fs, null,Path.GetFileName(file_)));
            for (int i = 0; i < nsbtx.textures.Length; i++)
            {
                listBox1.Items.Add(nsbtx.textures[i].name);
            }
            for (int i = 0; i < nsbtx.palettes.Length; i++)
            {
                listBox2.Items.Add(nsbtx.palettes[i].name);
            }*/
            EndianBinaryReader er = new EndianBinaryReader(File.OpenRead(file_), Endianness.LittleEndian);
            nsbtx = new NSBTX_File();
            if (er.ReadString(Encoding.ASCII, 4) != "BTX0")
            {
                bool found = false;
                int startpos = 0;
                while (er.BaseStream.Length - er.BaseStream.Position != 4)
                {
                    nsbtx.TEX0.ID = er.ReadString(Encoding.ASCII, 4);
                    if (nsbtx.TEX0.ID == "TEX0") // "TEX0"
                    {
                        startpos = (int)er.BaseStream.Position - 4;
                        found = true;
                        break;
                    }
                }
                if (found)
                {
                    er.BaseStream.Position = 0;
                    nsbtx.Before = er.ReadBytes(startpos);
                    er.ReadBytes(4);
                    nsbtx.Header.Section_Offset = new int[1];
                    nsbtx.Header.Section_Offset[0] = startpos;
                }
                else
                {
                    MessageBox.Show("Error");
                    er.Close();
                    this.Close();
                }
            }
            else
            {
                nsbtx.Header.ID = "BTX0";
                nsbtx.Header.Magic = er.ReadBytes(4);
                nsbtx.Header.file_size = er.ReadInt32();
                nsbtx.Header.header_size = er.ReadInt16();
                nsbtx.Header.nSection = er.ReadInt16();
                nsbtx.Header.Section_Offset = new Int32[nsbtx.Header.nSection];
                for (int i = 0; i < nsbtx.Header.nSection; i++)
                {
                    nsbtx.Header.Section_Offset[i] = er.ReadInt32();
                }
                nsbtx.TEX0.ID = er.ReadString(Encoding.ASCII, 4);
                if (nsbtx.TEX0.ID != "TEX0")
                {
                    MessageBox.Show("Error");
                    er.Close();
                    this.Close();
                }
            }
            nsbtx.TEX0.Section_size = er.ReadInt32();
            nsbtx.TEX0.Padding1 = er.ReadInt32();
            nsbtx.TEX0.Texture_Data_Size = (er.ReadInt16() << 3);
            nsbtx.TEX0.Texture_Info_Offset = er.ReadInt16();
            nsbtx.TEX0.Padding2 = er.ReadInt32();
            nsbtx.TEX0.Texture_Data_Offset = er.ReadInt32();
            nsbtx.TEX0.Padding3 = er.ReadInt32();
            nsbtx.TEX0.Compressed_Texture_Data_Size = (er.ReadInt16() << 3);
            nsbtx.TEX0.Compressed_Texture_Info_Offset = er.ReadInt16();
            nsbtx.TEX0.Padding4 = er.ReadInt32();
            nsbtx.TEX0.Compressed_Texture_Data_Offset = er.ReadInt32();
            nsbtx.TEX0.Compressed_Texture_Info_Data_Offset = er.ReadInt32();
            nsbtx.TEX0.Padding5 = er.ReadInt32();
            nsbtx.TEX0.Palette_Data_Size = (er.ReadInt32() << 3);
            nsbtx.TEX0.Palette_Info_Offset = er.ReadInt32();
            nsbtx.TEX0.Palette_Data_Offset = er.ReadInt32();

            nsbtx.TexInfo.dummy = er.ReadByte();
            nsbtx.TexInfo.num_objs = er.ReadByte();
            nsbtx.TexInfo.section_size = er.ReadInt16();

            nsbtx.TexInfo.unknownBlock.header_size = er.ReadInt16();
            nsbtx.TexInfo.unknownBlock.section_size = er.ReadInt16();
            nsbtx.TexInfo.unknownBlock.constant = er.ReadInt32();
            nsbtx.TexInfo.unknownBlock.unknown1 = new short[nsbtx.TexInfo.num_objs];
            nsbtx.TexInfo.unknownBlock.unknown2 = new short[nsbtx.TexInfo.num_objs];
            for (int i = 0; i < nsbtx.TexInfo.num_objs; i++)
            {
                nsbtx.TexInfo.unknownBlock.unknown1[i] = er.ReadInt16();
                nsbtx.TexInfo.unknownBlock.unknown2[i] = er.ReadInt16();
            }

            nsbtx.TexInfo.infoBlock.header_size = er.ReadInt16();
            nsbtx.TexInfo.infoBlock.data_size = er.ReadInt16();
            nsbtx.TexInfo.infoBlock.TexInfo = new NSBTX_File.texInfo.Info.texInfo[nsbtx.TexInfo.num_objs];
            //long compressedStartOffset = 0x00;
            for (int i = 0; i < nsbtx.TexInfo.num_objs; i++)
            {
                nsbtx.TexInfo.infoBlock.TexInfo[i].Texture_Offset = (er.ReadInt16() << 3);
                nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters = er.ReadInt16();
                nsbtx.TexInfo.infoBlock.TexInfo[i].Width = er.ReadByte();
                nsbtx.TexInfo.infoBlock.TexInfo[i].Unknown1 = er.ReadByte();
                nsbtx.TexInfo.infoBlock.TexInfo[i].Height = er.ReadByte();
                nsbtx.TexInfo.infoBlock.TexInfo[i].Unknown2 = er.ReadByte();
                nsbtx.TexInfo.infoBlock.TexInfo[i].coord_transf = (byte)(nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters & 14);
                nsbtx.TexInfo.infoBlock.TexInfo[i].color0 = (byte)((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 13) & 1);
                nsbtx.TexInfo.infoBlock.TexInfo[i].format = (byte)((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 10) & 7);
                nsbtx.TexInfo.infoBlock.TexInfo[i].height = (byte)(8 << ((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 7) & 7));
                nsbtx.TexInfo.infoBlock.TexInfo[i].width = (byte)(8 << ((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 4) & 7));
                nsbtx.TexInfo.infoBlock.TexInfo[i].flip_Y = (byte)((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 3) & 1);
                nsbtx.TexInfo.infoBlock.TexInfo[i].flip_X = (byte)((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 2) & 1);
                nsbtx.TexInfo.infoBlock.TexInfo[i].repeat_Y = (byte)((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 1) & 1);
                nsbtx.TexInfo.infoBlock.TexInfo[i].repeat_X = (byte)(nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters & 1);
                nsbtx.TexInfo.infoBlock.TexInfo[i].depth = (byte)bpp[nsbtx.TexInfo.infoBlock.TexInfo[i].format];
                if (nsbtx.TexInfo.infoBlock.TexInfo[i].width == 0x00)
                    switch (nsbtx.TexInfo.infoBlock.TexInfo[i].Unknown1 & 0x3)
                    {
                        case 2:
                            nsbtx.TexInfo.infoBlock.TexInfo[i].width = 0x200;
                            break;
                        default:
                            nsbtx.TexInfo.infoBlock.TexInfo[i].width = 0x100;
                            break;
                    }
                if (nsbtx.TexInfo.infoBlock.TexInfo[i].height == 0x00)
                    switch ((nsbtx.TexInfo.infoBlock.TexInfo[i].Height >> 3) & 0x3)
                    {
                        case 2:
                            nsbtx.TexInfo.infoBlock.TexInfo[i].height = 0x200;
                            break;
                        default:
                            nsbtx.TexInfo.infoBlock.TexInfo[i].height = 0x100;
                            break;
                    }
                int imgsize = (nsbtx.TexInfo.infoBlock.TexInfo[i].width * nsbtx.TexInfo.infoBlock.TexInfo[i].height * nsbtx.TexInfo.infoBlock.TexInfo[i].depth) / 8;
                long curpos = er.BaseStream.Position;
                if (nsbtx.TexInfo.infoBlock.TexInfo[i].format != 5)
                {
                    er.BaseStream.Seek(nsbtx.TexInfo.infoBlock.TexInfo[i].Texture_Offset + nsbtx.Header.Section_Offset[0] + nsbtx.TEX0.Texture_Data_Offset, SeekOrigin.Begin);
                }
                else
                {
                    er.BaseStream.Seek(nsbtx.Header.Section_Offset[0] + nsbtx.TEX0.Compressed_Texture_Data_Offset + nsbtx.TexInfo.infoBlock.TexInfo[i].Texture_Offset, SeekOrigin.Begin);
                }
                nsbtx.TexInfo.infoBlock.TexInfo[i].Image = er.ReadBytes(imgsize);
                er.BaseStream.Seek(curpos, SeekOrigin.Begin);

                if (nsbtx.TexInfo.infoBlock.TexInfo[i].format == 5)
                {
                    //nsbtx.TexInfo.infoBlock.TexInfo[i].compressedDataStart = (uint)compressedStartOffset;
                    //compressedStartOffset += imgsize / 2;
                    curpos = er.BaseStream.Position;
                    er.BaseStream.Seek(nsbtx.Header.Section_Offset[0] + nsbtx.TEX0.Compressed_Texture_Info_Data_Offset + nsbtx.TexInfo.infoBlock.TexInfo[i].Texture_Offset / 2, SeekOrigin.Begin);
                    nsbtx.TexInfo.infoBlock.TexInfo[i].spData = er.ReadBytes(imgsize / 2);
                    er.BaseStream.Seek(curpos, SeekOrigin.Begin);
                }
            }
            nsbtx.TexInfo.names = new string[nsbtx.TexInfo.num_objs];
            for (int i = 0; i < nsbtx.TexInfo.num_objs; i++)
            {
                nsbtx.TexInfo.names[i] = er.ReadString(Encoding.ASCII, 16).Replace("\0", "");
                listBox1.Items.Add(nsbtx.TexInfo.names[i]);
            }

            nsbtx.PalInfo.dummy = er.ReadByte();
            nsbtx.PalInfo.num_objs = er.ReadByte();
            nsbtx.PalInfo.section_size = er.ReadInt16();

            nsbtx.PalInfo.unknownBlock.header_size = er.ReadInt16();
            nsbtx.PalInfo.unknownBlock.section_size = er.ReadInt16();
            nsbtx.PalInfo.unknownBlock.constant = er.ReadInt32();
            nsbtx.PalInfo.unknownBlock.unknown1 = new short[nsbtx.PalInfo.num_objs];
            nsbtx.PalInfo.unknownBlock.unknown2 = new short[nsbtx.PalInfo.num_objs];
            for (int i = 0; i < nsbtx.PalInfo.num_objs; i++)
            {
                nsbtx.PalInfo.unknownBlock.unknown1[i] = er.ReadInt16();
                nsbtx.PalInfo.unknownBlock.unknown2[i] = er.ReadInt16();
            }

            nsbtx.PalInfo.infoBlock.header_size = er.ReadInt16();
            nsbtx.PalInfo.infoBlock.data_size = er.ReadInt16();
            nsbtx.PalInfo.infoBlock.PalInfo = new NSBTX_File.palInfo.Info.palInfo[nsbtx.PalInfo.num_objs];
            for (int i = 0; i < nsbtx.PalInfo.num_objs; i++)
            {
                nsbtx.PalInfo.infoBlock.PalInfo[i].Palette_Offset = (er.ReadInt16() << 3);
                nsbtx.PalInfo.infoBlock.PalInfo[i].Color0 = er.ReadInt16();
                er.BaseStream.Position -= 4;
                int palBase = er.ReadInt32();
                int palAddr = palBase & 0xfff;
                long curpos = er.BaseStream.Position;
                er.BaseStream.Seek(nsbtx.Header.Section_Offset[0] + nsbtx.TEX0.Palette_Data_Offset, SeekOrigin.Begin);
                er.BaseStream.Seek(nsbtx.PalInfo.infoBlock.PalInfo[i].Palette_Offset, SeekOrigin.Current);
                nsbtx.PalInfo.infoBlock.PalInfo[i].pal = Tinke.Convertir.BGR555(er.ReadBytes(nsbtx.TEX0.Palette_Data_Size - nsbtx.PalInfo.infoBlock.PalInfo[i].Palette_Offset));
                er.BaseStream.Seek(curpos, SeekOrigin.Begin);
            }
            nsbtx.PalInfo.names = new string[nsbtx.PalInfo.num_objs];
            for (int i = 0; i < nsbtx.PalInfo.num_objs; i++)
            {
                nsbtx.PalInfo.names[i] = er.ReadString(Encoding.ASCII, 16).Replace("\0", "");
                listBox2.Items.Add(nsbtx.PalInfo.names[i]);
            }
            List<int> offsets = new List<int>();
            for (int i = 0; i < nsbtx.PalInfo.num_objs; i++)
            {
                //if(!offsets.Contains(nsbtx.PalInfo.infoBlock.PalInfo[i].Palette_Offset))
                //{
                offsets.Add(nsbtx.PalInfo.infoBlock.PalInfo[i].Palette_Offset);
                //}
            }
            offsets.Add((int)er.BaseStream.Length);
            offsets.Sort();
            for (int i = 0; i < nsbtx.PalInfo.num_objs; i++)
            {
                int pallength;
                int j = -1;
                do
                {
                    j++;
                }
                while (offsets[j] - nsbtx.PalInfo.infoBlock.PalInfo[i].Palette_Offset <= 0);//nsbtx.PalInfo.infoBlock.PalInfo[i + j].Palette_Offset - nsbtx.PalInfo.infoBlock.PalInfo[i].Palette_Offset == 0)
                pallength = offsets[j] - nsbtx.PalInfo.infoBlock.PalInfo[i].Palette_Offset;
                Color[] c_ = nsbtx.PalInfo.infoBlock.PalInfo[i].pal;
                List<Color> c = new List<Color>();
                c.AddRange(nsbtx.PalInfo.infoBlock.PalInfo[i].pal.Take(pallength / 2));
                nsbtx.PalInfo.infoBlock.PalInfo[i].pal = c.ToArray();
            }
            er.Close();
            listBox1.SelectedIndex = 0;
        }
        private void nsbtx__Load(object sender, EventArgs e)
        {
            load();
        }
        int[] bpp = { 0, 8, 2, 4, 8, 2, 8, 16 };
        //static int[] PaletteSize = new int[] { 0x00, 0x40, 0x08, 0x20, 0x200, 0x200, 0x10, 0x00 };
        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listBox1.SelectedIndex == -1)
            {
                listBox1.SelectedIndex = 0;
            }
            if (listBox2.SelectedIndex == -1 && nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].format != 7)
            {
                listBox2.SelectedIndex = 0;
            }
            if (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].format == 7)
            {
                type1ToolStripMenuItem.Enabled = false;
                toolStripMenuItem2.Enabled = false;
                colorPaletteTextureToolStripMenuItem.Enabled = false;
                colorPaletteTextureToolStripMenuItem1.Enabled = false;
                x4TexelCompressedTextureToolStripMenuItem.Enabled = false;
                a5I3TranslucentTexture5bitAlpha3bitColorIndexToolStripMenuItem.Enabled = false;
                directColorTextureToolStripMenuItem.Enabled = true;
            }
            else
            {
                type1ToolStripMenuItem.Enabled = true;
                toolStripMenuItem2.Enabled = true;
                colorPaletteTextureToolStripMenuItem.Enabled = true;
                colorPaletteTextureToolStripMenuItem1.Enabled = true;
                x4TexelCompressedTextureToolStripMenuItem.Enabled = true;
                a5I3TranslucentTexture5bitAlpha3bitColorIndexToolStripMenuItem.Enabled = true;
                directColorTextureToolStripMenuItem.Enabled = false;
            }
            /*NSMBe4.DSFileSystem.ExternalFilesystemSource f = new NSMBe4.DSFileSystem.ExternalFilesystemSource(file_);
            NSMBe4.DSFileSystem.Filesystem fs = new NSMBe4.DSFileSystem.Filesystem(f);
            NSMBe4.NSBMD.NSBTX nsbtx = new NSMBe4.NSBMD.NSBTX(new NSMBe4.DSFileSystem.File(fs, null, Path.GetFileName(file_)));
            pictureBox1.Image = nsbtx.textures[listBox1.SelectedIndex].render(nsbtx.pal[listBox2.SelectedIndex]);*/
            Bitmap b_ = new Bitmap(nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width, nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].height);
            NSMBe4.NSBMD.ImageTexeler.LockBitmap b = new NSMBe4.NSBMD.ImageTexeler.LockBitmap(b_);
            b.LockBits();
            int pixelnum = b.Height * b.Width;
            try
            {
                switch (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].format)
                {
                    case 1:
                        for (int j = 0; j < pixelnum; j++)
                        {
                            int index = nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].Image[j] & 0x1f;
                            int alpha = (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].Image[j] >> 5);
                            alpha = ((alpha * 4) + (alpha / 2)) * 8;
                            Color c = Color.FromArgb(alpha, nsbtx.PalInfo.infoBlock.PalInfo[listBox2.SelectedIndex].pal[index]);
                            b.SetPixel(j - ((j / (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width)) * (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width)), j / (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width), c);
                        }
                        b.UnlockBits();
                        break;
                    case 2:
                        for (int j = 0; j < pixelnum; j++)
                        {
                            uint index = nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].Image[j / 4];
                            index = (index >> ((j % 4) << 1)) & 3;
                            if (index == 0 && nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].color0 == 1)
                            {
                                b.SetPixel(j - ((j / (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width)) * (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width)), j / (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width), Color.Transparent);
                            }
                            else
                            {
                                b.SetPixel(j - ((j / (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width)) * (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width)), j / (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width), nsbtx.PalInfo.infoBlock.PalInfo[listBox2.SelectedIndex].pal[index]);
                            }
                        }
                        b.UnlockBits();
                        //if (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].color0 == 1) { b_.MakeTransparent(nsbtx.PalInfo.infoBlock.PalInfo[listBox2.SelectedIndex].pal[0]); }
                        break;
                    case 3:
                        //sp.PLTO[listBox1.SelectedIndex].Pal[sp.PLTO[listBox1.SelectedIndex].Unknown] = Color.Transparent; // made palette entry 0 transparent
                        for (int j = 0; j < pixelnum; j++)
                        {
                            uint index = nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].Image[j / 2];
                            index = (index >> ((j % 2) << 2)) & 0x0f;
                            if (index == 0 && nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].color0 == 1)
                            {
                                b.SetPixel(j - ((j / (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width)) * (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width)), j / (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width), Color.Transparent);
                            }
                            else
                            {
                                b.SetPixel(j - ((j / (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width)) * (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width)), j / (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width), nsbtx.PalInfo.infoBlock.PalInfo[listBox2.SelectedIndex].pal[index]);
                            }
                        }
                        b.UnlockBits();
                        //if (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].color0 == 1) { b_.MakeTransparent(nsbtx.PalInfo.infoBlock.PalInfo[listBox2.SelectedIndex].pal[0]); }
                        break;
                    case 4:
                        //if (mat.color0 != 0) mat.paldata[0] = RGBA.Transparent; // made palette entry 0 transparent
                        for (int j = 0; j < pixelnum; j++)
                        {
                            byte index = nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].Image[j];
                            if(index == 0 && nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].color0 == 1)
                            {
                                b.SetPixel(j - ((j / (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width)) * (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width)), j / (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width), Color.Transparent);
                            }
                            else
                            {
                                b.SetPixel(j - ((j / (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width)) * (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width)), j / (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width), nsbtx.PalInfo.infoBlock.PalInfo[listBox2.SelectedIndex].pal[index]);
                            }
                        }
                        b.UnlockBits();
                        break;
                    case 5:
                        convert_4x4texel_b(nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].Image, nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width, nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].height, nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].spData, nsbtx.PalInfo.infoBlock.PalInfo[listBox2.SelectedIndex].pal, b);
                        b.UnlockBits();
                        break;
                    case 6:
                        for (int j = 0; j < pixelnum; j++)
                        {
                            int index = nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].Image[j] & 0x7;
                            int alpha = (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].Image[j] >> 3);// & 0x1f;
                            alpha *= 8;
                            Color c = Color.FromArgb(alpha, nsbtx.PalInfo.infoBlock.PalInfo[listBox2.SelectedIndex].pal[index]);
                            b.SetPixel(j - ((j / (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width)) * (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width)), j / (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width), c);
                        }
                        b.UnlockBits();
                        break;
                    case 7:
                        for (int j = 0; j < pixelnum; j++)
                        {
                            UInt16 p = (ushort)(nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].Image[j * 2] + (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].Image[j * 2 + 1] << 8));
                            Color c = Color.FromArgb((((p & 0x8000) != 0) ? 0xff : 0), (((p >> 0) & 0x1f) << 3), (((p >> 5) & 0x1f) << 3), (((p >> 10) & 0x1f) << 3));
                            b.SetPixel(j - ((j / (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width)) * (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width)), j / (nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width), c);
                        }
                        b.UnlockBits();
                        break;
                }
            }
            catch
            {
                b.UnlockBits();
                goto end2;
            }
        end2:
            pictureBox1.Image = b_;
        }
        /// <summary>
        /// Convert texel.
        /// </summary>
        private bool convert_4x4texel(uint[] tex, int width, int height, UInt16[] data, Color[] pal, NSMBe4.NSBMD.ImageTexeler.LockBitmap rgbaOut)
        {
            int w = width / 4;
            int h = height / 4;

            // traverse 'w x h blocks' of 4x4-texel
            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                {
                    int index = y * w + x;
                    UInt32 t = tex[index];
                    UInt16 d = data[index];
                    UInt16 addr = (ushort)(d & 0x3fff);
                    UInt16 mode = (ushort)((d >> 14) & 3);

                    // traverse every texel in the 4x4 texels
                    for (int r = 0; r < 4; r++)
                        for (int c = 0; c < 4; c++)
                        {
                            int texel = (int)((t >> ((r * 4 + c) * 2)) & 3);
                            Color pixel = rgbaOut.GetPixel((x * 4 + c), (y * 4 + r));

                            switch (mode)
                            {
                                case 0:
                                    pixel = pal[(addr << 1) + texel];
                                    if (texel == 3) pixel = Color.Transparent; // make it transparent, alpha = 0
                                    break;
                                case 2:
                                    pixel = pal[(addr << 1) + texel];
                                    break;
                                case 1:
                                    switch (texel)
                                    {
                                        case 0:
                                        case 1:
                                            pixel = pal[(addr << 1) + texel];
                                            break;
                                        case 2:
                                            byte R = (byte)((pal[(addr << 1)].R + pal[(addr << 1) + 1].R) / 2L);
                                            byte G = (byte)((pal[(addr << 1)].G + pal[(addr << 1) + 1].G) / 2L);
                                            byte B = (byte)((pal[(addr << 1)].B + pal[(addr << 1) + 1].B) / 2L);
                                            byte A = 0xff;
                                            pixel = Color.FromArgb(A, R,G,B);
                                            break;
                                        case 3:
                                            pixel = Color.Transparent; // make it transparent, alpha = 0
                                            break;
                                    }
                                    break;
                                case 3:
                                    switch (texel)
                                    {
                                        case 0:
                                        case 1:
                                            pixel = pal[(addr << 1) + texel];
                                            break;
                                        case 2:
                                            {
                                                byte R = (byte)((pal[(addr << 1)].R * 5L + pal[(addr << 1) + 1].R * 3L) / 8);
                                                byte G = (byte)((pal[(addr << 1)].G * 5L + pal[(addr << 1) + 1].G * 3L) / 8);
                                                byte B = (byte)((pal[(addr << 1)].B * 5L + pal[(addr << 1) + 1].B * 3L) / 8);
                                                byte A = 0xff;
                                                pixel = Color.FromArgb(A, R, G, B);
                                                break;
                                            }
                                        case 3:
                                            {
                                                byte R = (byte)((pal[(addr << 1)].R * 3L + pal[(addr << 1) + 1].R * 5L) / 8);
                                                byte G = (byte)((pal[(addr << 1)].G * 3L + pal[(addr << 1) + 1].G * 5L) / 8);
                                                byte B = (byte)((pal[(addr << 1)].B * 3L + pal[(addr << 1) + 1].B * 5L) / 8);
                                                byte A = 0xff;
                                                pixel = Color.FromArgb(A, R, G, B);
                                                break;
                                            }
                                    }
                                    break;
                            }
                            rgbaOut.SetPixel((x * 4 + c), (y * 4 + r), pixel);
                            //rgbaOut[(y * 4 + r) * width + (x * 4 + c)] = pixel;
                        }
                }
            return true;
        }

        /// <summary>
        /// Convert texel (wrapper for type safety issues).
        /// </summary>
        private void convert_4x4texel_b(byte[] tex, int width, int height, byte[] data, Color[] pal, NSMBe4.NSBMD.ImageTexeler.LockBitmap rgbaOut)
        {
            var list1 = new List<uint>();
            for (int i = 0; i < (tex.Length + 1) / 4; ++i)
                list1.Add(LibNDSFormats.Utils.Read4BytesAsUInt32(tex, i * 4));

            var list2 = new List<UInt16>();
            for (int i = 0; i < (data.Length + 1) / 2; ++i)
                list2.Add(LibNDSFormats.Utils.Read2BytesAsUInt16(data, i * 2));
            var b = convert_4x4texel(list1.ToArray(), width, height, list2.ToArray(), pal, rgbaOut);
        }

        private void nsbtx__Shown(object sender, EventArgs e)
        {

        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            saveFileDialog1.FileName = nsbtx.TexInfo.names[listBox1.SelectedIndex]+".png";
            if (saveFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK
                && saveFileDialog1.FileName.Length > 0)
            {
                pictureBox1.Image.Save(saveFileDialog1.FileName, System.Drawing.Imaging.ImageFormat.Png);
            }
        }

        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            CreateTexture();
        }
        void CreateTexture()
        {
            CreateTexture(nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].format);
        }
        void CreateTexture(int type)
        {
            CreateTexture(type, -1);
        }
        void CreateTexture(int type, int type5colors)
        {
            if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK
                && openFileDialog1.FileName.Length > 0)
            {
                Bitmap b = new Bitmap(Bitmap.FromFile(openFileDialog1.FileName));
                int width = 8, height = 8;
                int dswidth = 0, dsheight = 0;
                while (width < b.Width /*&& (width*2 > b.Width) == false*/) { width *= 2; dswidth++; }
                while (height < b.Height /*&& (height * 2 > b.Height) == false*/) { height *= 2; dsheight++; }
                if (type == 5 && height > 256 || width > 256)
                {
                    height = 256;//b.Height > b.Width ? 1024 : 512;
                    width = 256;//b.Width > b.Height ? 1024 : 512;
                }
                // cheap resizing for textures whose dimensions aren't power-of-two
                if ((width < b.Width) || (height < b.Height))
                {
                    int newWidth, newHeight;
                    if (b.Height > b.Width)
                    {
                        newHeight = (int)height;
                        newWidth = (int)(b.Width * width / b.Height);
                    }
                    else
                    {
                        newWidth = (int)width;
                        newHeight = (int)(b.Height * height / b.Width);
                    }
                    MessageBox.Show("The picture isn't a power of 2. It will be resized. It can be that there is a transparent border around the picture.");
                    Bitmap newImage = new Bitmap(width, height);
                    using (Graphics gr = Graphics.FromImage(newImage))
                    {
                        gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                        gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                        gr.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
                        // gr.DrawImage(b, new Rectangle(0, 0, (int)((float)width * ((float)b.Height / (float)b.Width)), (int)((float)height * ((float)b.Height / (float)b.Width))));
                        gr.DrawImage(b, new Rectangle(0, 0, newWidth, newHeight));
                    }
                    b = newImage;
                }
                else
                {
                    Bitmap newImage = new Bitmap(width, height);
                    using (Graphics gr = Graphics.FromImage(newImage))
                    {
                        gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                        gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                        gr.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
                        gr.DrawImage(b, new Rectangle(0, 0, b.Width, b.Height));
                    }
                    b = newImage;
                }
                if (type != 5)
                {
                    Color[] c_ = new Color[0];
                    bool trans = false;
                    if (type == 4 || type == 3 || type == 2)
                    {
                        for (int x = 0; x < b.Width; x++)
                            for (int y = 0; y < b.Height; y++)
                            {
                                if (b.GetPixel(x, y).A == 0)
                                {
                                    trans = true;
                                }
                            }
                        switch (type)
                        {
                            case 2:
                                c_ = ImageIndexer.createPaletteForImage(b, 4, trans);
                                break;
                            case 3:
                                c_ = ImageIndexer.createPaletteForImage(b, 16, trans);
                                break;
                            case 4:
                                c_ = ImageIndexer.createPaletteForImage(b, 256, trans);
                                break;
                        }

                    }
                    else if (type != 7)
                    {
                        switch (type)
                        {
                            case 1:
                                c_ = ImageIndexer.createPaletteForImage(b, 32, false);
                                break;
                            case 6:
                                c_ = ImageIndexer.createPaletteForImage(b, 8, false);
                                break;
                        }
                    }
                    List<byte> pic = new List<byte>();
                    switch (type)
                    {
                        case 1:
                        case 4:
                        case 6:
                            pic.AddRange(new byte[(b.Width * b.Height)]);
                            break;
                        case 2:
                        case 5:
                            pic.AddRange(new byte[(b.Width * b.Height) / 4]);
                            break;
                        case 3:
                            pic.AddRange(new byte[(b.Width * b.Height) / 2]);
                            break;
                        case 7:
                            pic.AddRange(new byte[(b.Width * b.Height) * 2]);
                            break;
                    }
                    bool use0 = false;
                    NSMBe4.NSBMD.ImageTexeler.LockBitmap bd = new NSMBe4.NSBMD.ImageTexeler.LockBitmap(b);
                    bd.LockBits();
                    for (int x = 0; x < b.Width; x++)
                        for (int y = 0; y < b.Height; y++)
                        {
                            Color c = bd.GetPixel(x, y);
                            if (c.A == 0) { use0 = true; };
                            int i = c.ToArgb();
                            if (trans)
                            {
                                if (type != 7 && c.A != 0) { i = getClosestColor(c, c_.ToList().GetRange(1, c_.Length - 1).ToArray()); i++; }
                                else if (c.A == 0) { i = 0; }
                            }
                            else
                            {
                                if (type != 7 && c.A != 0) { i = getClosestColor(c, c_); }
                            }
                            pic = setPixel(x, y, i, b.Width, b.Height, type, pic, c.A);
                        }
                    bd.UnlockBits();
                    byte[] b_ = pic.ToArray();
                    if (use0/* && c_.Contains(Color.Transparent)*/ && (type == 4 || type == 3 || type == 2))
                    {
                        /*if (c_.Contains(Color.Fuchsia) == false)
                        {
                            c_[0] = Color.Fuchsia;
                        }
                        else*/
                        {
                            c_[0] = Color.Fuchsia;
                        }
                        nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].color0 = 1;
                    }
                    else { nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].color0 = 0; }
                    nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].Image = b_;
                    nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].height = (ushort)b.Height;
                    nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].width = (ushort)b.Width;
                    nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].spData = new byte[0];
                    nsbtx.TexInfo.infoBlock.TexInfo[listBox1.SelectedIndex].format = (byte)type;


                    if (type != 7) { nsbtx.PalInfo.infoBlock.PalInfo[listBox2.SelectedIndex].pal = c_; }
                    listBox1.SetSelected(listBox1.SelectedIndex, true);
                }
                else
                {
                    BackgroundWorker bw = new BackgroundWorker();
                    bw.WorkerReportsProgress = true;
                    bw.WorkerSupportsCancellation = true;
                    bw.DoWork += new DoWorkEventHandler(tex4x4);
                    bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
                    bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
                    bw.RunWorkerAsync(new object[] { listBox1.SelectedIndex, listBox2.SelectedIndex, b, type5colors });
                    bwr = bw;
                    toolStripDropDownButton1.Enabled = true;


                    listBox1.SetSelected(listBox1.SelectedIndex, true);
                }
            }
        }
        private static Rectangle EnsureAspectRatio(Image Image, int Width, int Height)
        {
            float AspectRatio = (float)Width / (float)Height;
            float CalculatedWidth = Image.Width, CalculatedHeight = Image.Height;

            if (Image.Width >= Image.Height)
            {
                if (Width > Height)
                {
                    CalculatedHeight = Image.Width / AspectRatio;
                    if (CalculatedHeight > Image.Height)
                    {
                        CalculatedHeight = Image.Height;
                        CalculatedWidth = CalculatedHeight * AspectRatio;
                    }
                }
                else
                {
                    CalculatedWidth = Image.Height * AspectRatio;
                    if (CalculatedWidth > Image.Width)
                    {
                        CalculatedWidth = Image.Width;
                        CalculatedHeight = CalculatedWidth / AspectRatio;
                    }
                }
            }
            else
            {
                if (Width < Height)
                {
                    CalculatedHeight = Image.Width / AspectRatio;
                    if (CalculatedHeight > Image.Height)
                    {
                        CalculatedHeight = Image.Height;
                        CalculatedWidth = CalculatedHeight * AspectRatio;
                    }
                }
                else
                {
                    CalculatedWidth = Image.Height * AspectRatio;
                    if (CalculatedWidth > Image.Width)
                    {
                        CalculatedWidth = Image.Width;
                        CalculatedHeight = CalculatedWidth / AspectRatio;
                    }
                }
            }
            return Rectangle.Ceiling(new RectangleF((Image.Width - CalculatedWidth) / 2, 0, CalculatedWidth, CalculatedHeight));
        }

        void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            listBox1.SetSelected((int)e.Result, true);
            bwr = null;
            toolStripDropDownButton1.Enabled = false;
        }

        void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            try
            {
                toolStripProgressBar1.Value = e.ProgressPercentage;
            }
            catch
            {

            }
            toolStripStatusLabel1.Text = (string)e.UserState;
        }

        void tex4x4(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker bw = (BackgroundWorker)sender;
            bw.ReportProgress(5);
            object[] SelectedIndex = (object[])e.Argument;
            Bitmap b = (Bitmap)SelectedIndex[2];
            NSMBe4.NSBMD.ImageTexeler it = new NSMBe4.NSBMD.ImageTexeler(b, (((int)SelectedIndex[3]) ==-1? nsbtx.PalInfo.infoBlock.PalInfo[(int)SelectedIndex[1]].pal.Length / 4: (int)SelectedIndex[3]), ref bw);
            if (bw.CancellationPending != true)
            {
                nsbtx.TexInfo.infoBlock.TexInfo[(int)SelectedIndex[0]].Image = it.texdata;
                nsbtx.TexInfo.infoBlock.TexInfo[(int)SelectedIndex[0]].format = 5;
                nsbtx.TexInfo.infoBlock.TexInfo[(int)SelectedIndex[0]].spData = it.f5data;
                nsbtx.TexInfo.infoBlock.TexInfo[(int)SelectedIndex[0]].height = (ushort)b.Height;
                nsbtx.TexInfo.infoBlock.TexInfo[(int)SelectedIndex[0]].width = (ushort)b.Width;
                nsbtx.TexInfo.infoBlock.TexInfo[(int)SelectedIndex[0]].color0 = 0;
                nsbtx.PalInfo.infoBlock.PalInfo[(int)SelectedIndex[1]].pal = it.finalPalette;
                bw.ReportProgress(100, "OK");
            }
            else
            {
                bw.ReportProgress(0, "Cancelled");
            }
            e.Result = (int)SelectedIndex[0];
        }
        public int getClosestColor(Color c, Color[] pal)
        {
            if (c.A == 0)
                return 0;

            int bestInd = 0;
            float bestDif = ImageIndexer.colorDifferenceWithoutAlpha(pal[0], c);

            for (int i = 0; i < pal.Length; i++)
            {
                float d = ImageIndexer.colorDifferenceWithoutAlpha(pal[i], c);
                if (d < bestDif)
                {
                    bestDif = d;
                    bestInd = i;
                }
            }

            return bestInd;
        }
        public List<byte> setPixel(int x, int y, int c, int width, int height, int format, List<byte> pic, int alpha)
        {
            List<byte> pic2 = pic;
            if (x < 0 || x >= width) return null;
            if (y < 0 || y >= height) return null;
            if (format == 1)
            {
                c &= 0x1F;
                c |= alpha & (~0x1F);
            }
            if (format == 6)
            {
                c &= 0x07;
                c |= alpha & (~0x07);
            }

            pic2 = setPixelVal(x, y, c, width, bpp[format], pic);
            return pic2;
        }
        private List<byte> setPixelVal(int x, int y, int v, int width, int bpp, List<byte> pic)
        {
            List<byte> pic2 = pic;
            int i = x + y * width;
            if (bpp == 8) { pic2[i] = (byte)v; return pic2; }
            else if (bpp == 16)
            {
                //pic2[i * 2] = (byte)(v & 0xFF);
                //pic2[(i * 2) + 1] = (byte)((v >> 8) & 0xFF);
                nclr_e en = new nclr_e();
                Int16 b = (short)en.encodeColor(v, en.BGR555);
                b |= (short)((Color.FromArgb(v).A == 0 ? ~0x8000 : 0x8000));
                pic2[i * 2] = BitConverter.GetBytes(b)[0];
                pic2[(i * 2) + 1] = BitConverter.GetBytes(b)[1];
                return pic2;
            }

            else if (bpp == 4)
            {
                int res = pic2[i / 2];
                res &= ~(0xF << ((i % 2) * 4));
                res |= (v & 0xF) << ((i % 2) * 4);
                pic2[i / 2] = (byte)res;
            }

            else if (bpp == 2)
            {
                int res = pic2[i / 4];
                res &= ~(0xF << ((i % 4) * 2));
                res |= (v & 0xF) << ((i % 4) * 2);
                pic2[i / 4] = (byte)res;
            }
            else
            {
                //throw new Exception("Unsupported BPP Value: " + bpp);
            }
            return pic2;
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            NSBMD.NSBTP t = null;
            if (file_.EndsWith("nsbmd"))
            {
                t = new NSBMD.NSBTP(file_.Replace("nsbmd", "nsbtp"));
            }
            else
            {
                t = new NSBMD.NSBTP(file_.Replace("nsbtx", "nsbtp"));
            }
            NSMBe4.DSFileSystem.ExternalFilesystemSource f = new NSMBe4.DSFileSystem.ExternalFilesystemSource(file_);
            NSMBe4.DSFileSystem.Filesystem fs = new NSMBe4.DSFileSystem.Filesystem(f);
            NSMBe4.NSBMD.NSBTX nsbtx = new NSMBe4.NSBMD.NSBTX(new NSMBe4.DSFileSystem.File(fs, null, Path.GetFileName(file_)));
            pictureBox1.Image = nsbtx.textures[listBox1.Items.IndexOf(t.texname[timer])].render(nsbtx.pal[listBox2.Items.IndexOf(t.palname[timer])]);
            if (timer != t.texcount - 1)
            {
                timer += 1;
            }
            else
            {
                timer = 0;
            }
        }

        private void toolStripButton3_CheckStateChanged(object sender, EventArgs e)
        {
            if (toolStripButton3.CheckState == CheckState.Checked)
            {
                toolStripButton3.Image = Properties.Resources.control_pause;
                timer1.Start();
            }
            else
            {
                toolStripButton3.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButton3.Image")));
                timer1.Stop();
            }
        }

        private void toolStripButton6_Click(object sender, EventArgs e)
        {
            if (timer > 0)
            {
                timer -= 1;
                NSBMD.NSBTP t = null;
                if (file_.EndsWith("nsbmd"))
                {
                    t = new NSBMD.NSBTP(file_.Replace("nsbmd", "nsbtp"));
                }
                else
                {
                    t = new NSBMD.NSBTP(file_.Replace("nsbtx", "nsbtp"));
                }
                NSMBe4.DSFileSystem.ExternalFilesystemSource f = new NSMBe4.DSFileSystem.ExternalFilesystemSource(file_);
                NSMBe4.DSFileSystem.Filesystem fs = new NSMBe4.DSFileSystem.Filesystem(f);
                NSMBe4.NSBMD.NSBTX nsbtx = new NSMBe4.NSBMD.NSBTX(new NSMBe4.DSFileSystem.File(fs, null, Path.GetFileName(file_)));
                pictureBox1.Image = nsbtx.textures[listBox1.Items.IndexOf(t.texname[timer])].render(nsbtx.pal[listBox2.Items.IndexOf(t.palname[timer])]);
            }
        }

        private void toolStripButton4_Click(object sender, EventArgs e)
        {
            NSBMD.NSBTP t = null;
            if (file_.EndsWith("nsbmd"))
            {
                t = new NSBMD.NSBTP(file_.Replace("nsbmd", "nsbtp"));
            }
            else
            {
                t = new NSBMD.NSBTP(file_.Replace("nsbtx", "nsbtp"));
            }
            NSMBe4.DSFileSystem.ExternalFilesystemSource f = new NSMBe4.DSFileSystem.ExternalFilesystemSource(file_);
            NSMBe4.DSFileSystem.Filesystem fs = new NSMBe4.DSFileSystem.Filesystem(f);
            NSMBe4.NSBMD.NSBTX nsbtx = new NSMBe4.NSBMD.NSBTX(new NSMBe4.DSFileSystem.File(fs, null, Path.GetFileName(file_)));
            if (timer < t.texcount - 1)
            {
                timer += 1;
                pictureBox1.Image = nsbtx.textures[listBox1.Items.IndexOf(t.texname[timer])].render(nsbtx.pal[listBox2.Items.IndexOf(t.palname[timer])]);
            }
        }

        private void toolStripButton8_Click(object sender, EventArgs e)
        {
            if (saveFileDialog2.ShowDialog() == System.Windows.Forms.DialogResult.OK
    && saveFileDialog2.FileName.Length > 0)
            {


                NSBMD.NSBTP t = null;
                if (file_.EndsWith("nsbmd"))
                {
                    t = new NSBMD.NSBTP(file_.Replace("nsbmd", "nsbtp"));
                }
                else
                {
                    t = new NSBMD.NSBTP(file_.Replace("nsbtx", "nsbtp"));
                }
                NSMBe4.DSFileSystem.ExternalFilesystemSource f = new NSMBe4.DSFileSystem.ExternalFilesystemSource(file_);
                NSMBe4.DSFileSystem.Filesystem fs = new NSMBe4.DSFileSystem.Filesystem(f);
                NSMBe4.NSBMD.NSBTX nsbtx = new NSMBe4.NSBMD.NSBTX(new NSMBe4.DSFileSystem.File(fs, null, Path.GetFileName(file_)));
                List<Image> b = new List<Image>();
                for (int i = 0; i < t.texcount; i++)
                {
                    b.Add(nsbtx.textures[listBox1.Items.IndexOf(t.texname[i])].render(nsbtx.pal[listBox2.Items.IndexOf(t.palname[i])]));
                }
                Tinke.Convertir.CrearGif(saveFileDialog2.FileName, b.ToArray(), 10, 0);
            }

        }

        public struct NSBTX_File
        {
            public byte[] Before;
            public byte[] Beafter;
            public header Header;
            public struct header
            {
                public string ID;
                public byte[] Magic;
                public Int32 file_size;
                public Int16 header_size;
                public Int16 nSection;
                public Int32[] Section_Offset;
            }
            public tex0 TEX0;
            public struct tex0
            {
                public string ID;
                public Int32 Section_size;
                public Int32 Padding1;
                public Int32 Texture_Data_Size; //shift << 3
                public Int16 Texture_Info_Offset;
                public Int32 Padding2;
                public Int32 Texture_Data_Offset;
                public Int32 Padding3;
                public Int32 Compressed_Texture_Data_Size; //shift << 3
                public Int16 Compressed_Texture_Info_Offset;
                public Int32 Padding4;
                public Int32 Compressed_Texture_Data_Offset;
                public Int32 Compressed_Texture_Info_Data_Offset;
                public Int32 Padding5;
                public Int32 Palette_Data_Size; //shift << 3
                public Int32 Palette_Info_Offset;
                public Int32 Palette_Data_Offset;
            }
            public texInfo TexInfo;
            public struct texInfo
            {
                public byte dummy;
                public byte num_objs;
                public short section_size;
                public UnknownBlock unknownBlock;
                public Info infoBlock;
                public string[] names;

                public struct UnknownBlock
                {
                    public short header_size;
                    public short section_size;
                    public int constant; // 0x017F

                    public short[] unknown1;
                    public short[] unknown2;
                }
                public struct Info
                {
                    public short header_size;
                    public short data_size;

                    public texInfo[] TexInfo;

                    public struct texInfo
                    {
                        public Int32 Texture_Offset; //shift << 3, relative to start of Texture Data
                        public Int16 Parameters;
                        public byte Width;
                        public byte Unknown1;
                        public byte Height;
                        public byte Unknown2;

                        public byte[] Image;
                        public byte[] spData;
                        // Parameters
                        public byte repeat_X;   // 0 = freeze; 1 = repeat
                        public byte repeat_Y;   // 0 = freeze; 1 = repeat
                        public byte flip_X;     // 0 = no; 1 = flip each 2nd texture (requires repeat)
                        public byte flip_Y;     // 0 = no; 1 = flip each 2nd texture (requires repeat)
                        public ushort width;      // 8 << width
                        public ushort height;     // 8 << height
                        public byte format;     // Texture format
                        public byte color0; // 0 = displayed; 1 = transparent
                        public byte coord_transf; // Texture coordination transformation mode

                        public byte depth;
                        public uint compressedDataStart;
                    }
                }
            }
            public palInfo PalInfo;
            public struct palInfo
            {
                public byte dummy;
                public byte num_objs;
                public short section_size;
                public UnknownBlock unknownBlock;
                public Info infoBlock;
                public string[] names;

                public struct UnknownBlock
                {
                    public short header_size;
                    public short section_size;
                    public int constant; // 0x017F

                    public short[] unknown1;
                    public short[] unknown2;
                }
                public struct Info
                {
                    public short header_size;
                    public short data_size;

                    public palInfo[] PalInfo;

                    public struct palInfo
                    {
                        public Int32 Palette_Offset; //shift << 3, relative to start of Palette Data
                        public Int16 Color0;
                        public Color[] pal;
                    }
                }
            }
        }

        private void toolStripButton9_Click(object sender, EventArgs e)
        {
            EndianBinaryWriter ew = new EndianBinaryWriter(File.Create(file_), Endianness.LittleEndian);
            if (nsbtx.Before != null)
            {
                ew.Write(nsbtx.Before, 0, nsbtx.Before.Length);
            }
            else
            {
                ew.Write("BTX0", Encoding.ASCII, false);
                ew.Write(nsbtx.Header.Magic, 0, 4);
                ew.Write((Int32)0);
                ew.Write((Int16)nsbtx.Header.header_size);
                ew.Write((Int16)nsbtx.Header.nSection);
                for (int i = 0; i < nsbtx.Header.nSection; i++)
                {
                    ew.Write((Int32)nsbtx.Header.Section_Offset[i]);
                }
            }
            ew.Write("TEX0", Encoding.ASCII, false);
            ew.Write((Int32)0);
            ew.Write((Int32)0);
            int tex_length = 0;
            int comp_tex_length = 0;
            int comp_inf_length = 0;
            int nrtex = 0;
            int nr5 = 0;
            for (int i = 0; i < nsbtx.TexInfo.num_objs; i++)
            {
                if (nsbtx.TexInfo.infoBlock.TexInfo[i].format == 5)
                {
                    comp_tex_length += nsbtx.TexInfo.infoBlock.TexInfo[i].Image.Length;
                    comp_inf_length += nsbtx.TexInfo.infoBlock.TexInfo[i].spData.Length;
                    nr5 += 1;
                }
                else
                {
                    tex_length += nsbtx.TexInfo.infoBlock.TexInfo[i].Image.Length;
                    nrtex += 1;
                }
            }
            ew.Write((Int16)(tex_length >> 3));
            ew.Write((Int16)nsbtx.TEX0.Texture_Info_Offset);
            ew.Write((Int32)0);
            ew.Write((Int32)nsbtx.TEX0.Texture_Data_Offset);
            ew.Write((Int32)0);
            ew.Write((Int16)(comp_tex_length >> 3));
            ew.Write((Int16)nsbtx.TEX0.Compressed_Texture_Info_Offset);
            ew.Write((Int32)0);
            int Compressed_Texture_Data_Offset = 0x3c + nsbtx.TexInfo.section_size + nsbtx.PalInfo.section_size + tex_length;
            ew.Write((Int32)Compressed_Texture_Data_Offset);
            int Compressed_Texture_Info_Data_Offset = Compressed_Texture_Data_Offset + comp_tex_length;
            ew.Write((Int32)Compressed_Texture_Info_Data_Offset);
            ew.Write((Int32)0);
            int pallength = 0;
            for (int i = 0; i < nsbtx.PalInfo.num_objs; i++)
            {
                pallength += nsbtx.PalInfo.infoBlock.PalInfo[i].pal.Length * 2;
            }
            ew.Write((Int32)(pallength >> 3));
            int Pal_Info_Offset = 0x3c + nsbtx.TexInfo.section_size;
            ew.Write((Int32)Pal_Info_Offset);
            int Pal_Data_Offset = Compressed_Texture_Info_Data_Offset + comp_inf_length;
            ew.Write((Int32)Pal_Data_Offset);
            //Nitro 3d
            ew.Write((byte)0);
            ew.Write((byte)nsbtx.TexInfo.num_objs);
            ew.Write((Int16)nsbtx.TexInfo.section_size);

            ew.Write((Int16)nsbtx.TexInfo.unknownBlock.header_size);
            ew.Write((Int16)nsbtx.TexInfo.unknownBlock.section_size);
            ew.Write((Int32)nsbtx.TexInfo.unknownBlock.constant);
            for (int i = 0; i < nsbtx.TexInfo.num_objs; i++)
            {
                ew.Write((Int16)nsbtx.TexInfo.unknownBlock.unknown1[i]);
                ew.Write((Int16)nsbtx.TexInfo.unknownBlock.unknown2[i]);
            }

            ew.Write((Int16)nsbtx.TexInfo.infoBlock.header_size);
            ew.Write((Int16)nsbtx.TexInfo.infoBlock.data_size);
            int texoff = 0;
            int comptexoff = 0;
            for (int i = 0; i < nsbtx.TexInfo.num_objs; i++)
            {
                if (nsbtx.TexInfo.infoBlock.TexInfo[i].format != 5)
                {
                    ew.Write((Int16)(texoff >> 3));
                    texoff += nsbtx.TexInfo.infoBlock.TexInfo[i].Image.Length;
                }
                else
                {
                    ew.Write((Int16)(comptexoff >> 3));
                    comptexoff += nsbtx.TexInfo.infoBlock.TexInfo[i].Image.Length;
                }
                //nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters = 0;
                /*nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters = BitHelper.SetBit(nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters, 1, Convert.ToBoolean(nsbtx.TexInfo.infoBlock.TexInfo[i].coord_transf));
                nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters = BitHelper.SetBit(nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters, 2, Convert.ToBoolean(nsbtx.TexInfo.infoBlock.TexInfo[i].color0));
                nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters = BitHelper.SetBits(nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters, nsbtx.TexInfo.infoBlock.TexInfo[i].format, 1, 3, 3);
                nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters = BitHelper.SetBits(nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters, (short)(8 >> nsbtx.TexInfo.infoBlock.TexInfo[i].height), 1, 6, 3);
                nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters = BitHelper.SetBits(nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters, (short)(8 >> nsbtx.TexInfo.infoBlock.TexInfo[i].width), 1, 9, 3);
                nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters = BitHelper.SetBit(nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters, 12, Convert.ToBoolean(nsbtx.TexInfo.infoBlock.TexInfo[i].flip_Y));
                nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters = BitHelper.SetBit(nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters, 13, Convert.ToBoolean(nsbtx.TexInfo.infoBlock.TexInfo[i].flip_X));
                nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters = BitHelper.SetBit(nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters, 14, Convert.ToBoolean(nsbtx.TexInfo.infoBlock.TexInfo[i].repeat_Y));
                nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters = BitHelper.SetBit(nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters, 15, Convert.ToBoolean(nsbtx.TexInfo.infoBlock.TexInfo[i].repeat_X));*/

                //nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters &= 14;
                //nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters |= (short)((nsbtx.TexInfo.infoBlock.TexInfo[i].coord_transf == 0 ? 0x4 : ~0x4));//(short)(nsbtx.TexInfo.infoBlock.TexInfo[i].coord_transf << 14);//(Int16)(nsbtx.TexInfo.infoBlock.TexInfo[i].coord_transf & ~14);
                //nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters &= 13;
                //nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters |= (short)((short)(nsbtx.TexInfo.infoBlock.TexInfo[i].color0) << 13);//(Int16)((nsbtx.TexInfo.infoBlock.TexInfo[i].color0 & ~1) << 13);
                //nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters &= 10;
                //nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters |= (short)((short)(nsbtx.TexInfo.infoBlock.TexInfo[i].format) << 10);//(Int16)((nsbtx.TexInfo.infoBlock.TexInfo[i].format & ~7) << 10);
                //nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters |= (short)((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 7) << 7);
                //nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters |= (short)((((nsbtx.TexInfo.infoBlock.TexInfo[i].height << 8) << 7) & ~7));//(short)((short)((short)(8 >> nsbtx.TexInfo.infoBlock.TexInfo[i].height) << 7) & 7);//(short)((((short)((short)(nsbtx.TexInfo.infoBlock.TexInfo[i].height << 8))) << 7));//(Int16)(8 >> ((nsbtx.TexInfo.infoBlock.TexInfo[i].height & ~7) << 7));
                //nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters |= (short)((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 4) << 4);
                //nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters |= (short)((((nsbtx.TexInfo.infoBlock.TexInfo[i].width << 8) << 7) & ~7));//(short)((short)((short)(8 >> nsbtx.TexInfo.infoBlock.TexInfo[i].width) << 4) & 7);//(short)((((short)((short)(nsbtx.TexInfo.infoBlock.TexInfo[i].width << 8))) << 4));//(Int16)(8 >> ((nsbtx.TexInfo.infoBlock.TexInfo[i].width & ~7) << 4));
                //nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters &= 1;
                //nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters |= (short)((nsbtx.TexInfo.infoBlock.TexInfo[i].flip_Y == 0 ? 0x1000 : ~0x1000));//(short)((short)(nsbtx.TexInfo.infoBlock.TexInfo[i].flip_Y) << 3);//(Int16)((nsbtx.TexInfo.infoBlock.TexInfo[i].flip_Y & ~1) << 3);
                //nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters &= 1;
                //nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters |= (short)((nsbtx.TexInfo.infoBlock.TexInfo[i].flip_X == 0 ? 0x2000 : ~0x2000));//(short)((short)(nsbtx.TexInfo.infoBlock.TexInfo[i].flip_X) << 2);//(Int16)((nsbtx.TexInfo.infoBlock.TexInfo[i].flip_X & ~1) << 2);
                //nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters &= 1;
                //nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters |= (short)((nsbtx.TexInfo.infoBlock.TexInfo[i].repeat_Y == 0 ? 0x4000 : ~0x4000));//(short)((short)(nsbtx.TexInfo.infoBlock.TexInfo[i].repeat_Y) << 1);//(Int16)((nsbtx.TexInfo.infoBlock.TexInfo[i].repeat_Y & ~1) << 1);
                //nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters &= 1;
                //nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters |= (short)((nsbtx.TexInfo.infoBlock.TexInfo[i].repeat_X == 0 ? 0x8000 : ~0x8000));//(short)((short)(nsbtx.TexInfo.infoBlock.TexInfo[i].repeat_X));//(Int16)(nsbtx.TexInfo.infoBlock.TexInfo[i].repeat_X & ~1);*/
                //nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters = (short)((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 7 + ((short)(nsbtx.TexInfo.infoBlock.TexInfo[i].height) >> 8)) << 7);

                int width = 8, height = 8;
                int dswidth = 0, dsheight = 0;
                while (width < nsbtx.TexInfo.infoBlock.TexInfo[i].width) { width *= 2; dswidth++; }
                while (height < nsbtx.TexInfo.infoBlock.TexInfo[i].height) { height *= 2; dsheight++; }

                //dswidth = (int)Math.Sqrt(width);
                //dsheight = (int)Math.Sqrt(height);
                nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters = (Int16)((dswidth << 4)
                    | (dsheight << 7)
                    | (nsbtx.TexInfo.infoBlock.TexInfo[i].format << 10)
                    | (nsbtx.TexInfo.infoBlock.TexInfo[i].color0 << 13)
                    | (nsbtx.TexInfo.infoBlock.TexInfo[i].flip_Y << 3)
                    | (nsbtx.TexInfo.infoBlock.TexInfo[i].flip_X << 2)
                    | (nsbtx.TexInfo.infoBlock.TexInfo[i].repeat_Y << 1)
                    | (nsbtx.TexInfo.infoBlock.TexInfo[i].repeat_X)
                    | (nsbtx.TexInfo.infoBlock.TexInfo[i].coord_transf << 14)
                    );

                /* nsbtx.TexInfo.infoBlock.TexInfo[i].coord_transf = (byte)(nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters & 14);
                  nsbtx.TexInfo.infoBlock.TexInfo[i].color0 = (byte)((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 13) & 1);
                  nsbtx.TexInfo.infoBlock.TexInfo[i].format = (byte)((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 10) & 7);
                  nsbtx.TexInfo.infoBlock.TexInfo[i].height = (byte)(8 << ((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 7) & 7));
                  nsbtx.TexInfo.infoBlock.TexInfo[i].width = (byte)(8 << ((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 4) & 7));
                  nsbtx.TexInfo.infoBlock.TexInfo[i].flip_Y = (byte)((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 3) & 1);
                  nsbtx.TexInfo.infoBlock.TexInfo[i].flip_X = (byte)((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 2) & 1);
                  nsbtx.TexInfo.infoBlock.TexInfo[i].repeat_Y = (byte)((nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters >> 1) & 1);
                  nsbtx.TexInfo.infoBlock.TexInfo[i].repeat_X = (byte)(nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters & 1);*/

                if (nsbtx.TexInfo.infoBlock.TexInfo[i].width >= 256)
                    switch (nsbtx.TexInfo.infoBlock.TexInfo[i].width)
                    {
                        case 0x400:
                            nsbtx.TexInfo.infoBlock.TexInfo[i].Unknown1 = 3;
                            break;
                        case 0x200:
                            nsbtx.TexInfo.infoBlock.TexInfo[i].Unknown1 = 2;
                            break;
                        case 0x100:
                            nsbtx.TexInfo.infoBlock.TexInfo[i].Unknown1 = 1;
                            break;
                    }

                if (nsbtx.TexInfo.infoBlock.TexInfo[i].height >= 256)
                    switch (nsbtx.TexInfo.infoBlock.TexInfo[i].height)
                    {
                        case 0x400:
                            nsbtx.TexInfo.infoBlock.TexInfo[i].Height = 3 << 3;
                            break;
                        case 0x200:
                            nsbtx.TexInfo.infoBlock.TexInfo[i].Height = 2 << 3;
                            break;
                        case 0x100:
                            nsbtx.TexInfo.infoBlock.TexInfo[i].Height = 1 << 3;
                            break;
                    }


                //nsbtx.TexInfo.infoBlock.TexInfo[i].Width = (byte)(nsbtx.TexInfo.infoBlock.TexInfo[i].width >> 3);
                ew.Write((Int16)nsbtx.TexInfo.infoBlock.TexInfo[i].Parameters);
                ew.Write((byte)nsbtx.TexInfo.infoBlock.TexInfo[i].Width);
                ew.Write((byte)nsbtx.TexInfo.infoBlock.TexInfo[i].Unknown1);
                ew.Write((byte)nsbtx.TexInfo.infoBlock.TexInfo[i].Height);
                ew.Write((byte)nsbtx.TexInfo.infoBlock.TexInfo[i].Unknown2);
            }
            for (int i = 0; i < nsbtx.TexInfo.num_objs; i++)
            {
                ew.Write(nsbtx.TexInfo.names[i], Encoding.ASCII, false);
                if (nsbtx.TexInfo.names[i].Length != 16)
                {
                    ew.Write(new byte[16 - nsbtx.TexInfo.names[i].Length], 0, 16 - nsbtx.TexInfo.names[i].Length);
                }
            }

            //Nitro 3d
            ew.Write((byte)0);
            ew.Write((byte)nsbtx.PalInfo.num_objs);
            ew.Write((Int16)nsbtx.PalInfo.section_size);

            ew.Write((Int16)nsbtx.PalInfo.unknownBlock.header_size);
            ew.Write((Int16)nsbtx.PalInfo.unknownBlock.section_size);
            ew.Write((Int32)nsbtx.PalInfo.unknownBlock.constant);
            for (int i = 0; i < nsbtx.PalInfo.num_objs; i++)
            {
                ew.Write((Int16)nsbtx.PalInfo.unknownBlock.unknown1[i]);
                ew.Write((Int16)nsbtx.PalInfo.unknownBlock.unknown2[i]);
            }

            ew.Write((Int16)nsbtx.PalInfo.infoBlock.header_size);
            ew.Write((Int16)nsbtx.PalInfo.infoBlock.data_size);
            int paloff = 0;
            List<int> paloffsets = new List<int>();
            List<bool> paluse = new List<bool>();
            for (int i = 0; i < nsbtx.PalInfo.num_objs; i++)
            {
                paloffsets.Add(paloff);
                paluse.Add(true);
                paloff += nsbtx.PalInfo.infoBlock.PalInfo[i].pal.Length * 2;
            }
            /*for (int i = 0; i < nsbtx.PalInfo.num_objs; i++)
            {
                for (int j = 0; j < nsbtx.PalInfo.num_objs; j++)
                {
                    if(i==j)continue;
                    if (paluse[j] == false) continue;
                    if (nsbtx.PalInfo.infoBlock.PalInfo[i].pal.Length == nsbtx.PalInfo.infoBlock.PalInfo[j].pal.Length)
                    {
                        int same = 0;
                        for (int k = 0; k < nsbtx.PalInfo.infoBlock.PalInfo[i].pal.Length; k++)
                        {
                            if (nsbtx.PalInfo.infoBlock.PalInfo[i].pal[k] == nsbtx.PalInfo.infoBlock.PalInfo[j].pal[k]) same++;
                        }
                        if (same == nsbtx.PalInfo.infoBlock.PalInfo[i].pal.Length)
                        {
                            paloffsets[i] = paloffsets[j];
                            paluse[i] = false;
                            for (int k = i+1; k < paloffsets.Count; k++)
                            {
                                if (paloffsets[k] != paloffsets[j])
                                {
                                    paloffsets[k] -= nsbtx.PalInfo.infoBlock.PalInfo[i].pal.Length * 2;
                                }
                            }
                            break;
                        }
                    }
                }
            }*/
            for (int i = 0; i < nsbtx.PalInfo.num_objs; i++)
            {
                ew.Write((Int16)(paloffsets[i] >> 3));
                //paloffsets.Add(paloff);
                //paloff += nsbtx.PalInfo.infoBlock.PalInfo[i].pal.Length * 2;
                ew.Write((Int16)(nsbtx.PalInfo.infoBlock.PalInfo[i].Color0));
            }
            for (int i = 0; i < nsbtx.PalInfo.num_objs; i++)
            {
                ew.Write(nsbtx.PalInfo.names[i], Encoding.ASCII, false);
                if (nsbtx.PalInfo.names[i].Length != 16)
                {
                    ew.Write(new byte[16 - nsbtx.PalInfo.names[i].Length], 0, 16 - nsbtx.PalInfo.names[i].Length);
                }
            }

            for (int i = 0; i < nsbtx.TexInfo.num_objs; i++)
            {
                if (nsbtx.TexInfo.infoBlock.TexInfo[i].format != 5)
                {
                    ew.Write(nsbtx.TexInfo.infoBlock.TexInfo[i].Image, 0, nsbtx.TexInfo.infoBlock.TexInfo[i].Image.Length);
                }
            }
            for (int i = 0; i < nsbtx.TexInfo.num_objs; i++)
            {
                if (nsbtx.TexInfo.infoBlock.TexInfo[i].format == 5)
                {
                    ew.Write(nsbtx.TexInfo.infoBlock.TexInfo[i].Image, 0, nsbtx.TexInfo.infoBlock.TexInfo[i].Image.Length);
                }
            }
            for (int i = 0; i < nsbtx.TexInfo.num_objs; i++)
            {
                if (nsbtx.TexInfo.infoBlock.TexInfo[i].format == 5)
                {
                    ew.Write(nsbtx.TexInfo.infoBlock.TexInfo[i].spData, 0, nsbtx.TexInfo.infoBlock.TexInfo[i].spData.Length);
                }
            }
            for (int i = 0; i < nsbtx.PalInfo.num_objs; i++)
            {
                if (paluse[i] == false) continue;
                nclr_e en = new nclr_e();
                List<Int16> palbyte = new List<Int16>();
                for (int j = 0; j < nsbtx.PalInfo.infoBlock.PalInfo[i].pal.Length; j++)
                {
                    Color color = nsbtx.PalInfo.infoBlock.PalInfo[i].pal[j];
                    int nc = 0;
                    nc = en.encodeColor(color.ToArgb(), en.BGR555);
                    palbyte.Add((Int16)nc);
                }
                ew.Write(palbyte.ToArray(), 0, palbyte.Count);
            }
            ew.BaseStream.Position = 8;
            ew.Write((Int32)ew.BaseStream.Length);
            if (nsbtx.Before == null)
            {
                ew.BaseStream.Position = 4 + nsbtx.Header.Section_Offset[0];
                ew.Write((Int32)ew.BaseStream.Length - nsbtx.Header.Section_Offset[0]);
            }
            else
            {
                ew.BaseStream.Position = 4 + nsbtx.Before.Length;
                ew.Write((Int32)ew.BaseStream.Length - nsbtx.Before.Length);
            }
            ew.Close();
        }

        private void toolStripDropDownButton1_Click(object sender, EventArgs e)
        {
            if (bwr != null)
            {
                bwr.CancelAsync();
            }
        }

        private void type1ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CreateTexture(1);
        }

        private void toolStripMenuItem2_Click(object sender, EventArgs e)
        {
            CreateTexture(2);
        }

        private void colorPaletteTextureToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CreateTexture(3);
        }

        private void colorPaletteTextureToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            CreateTexture(4);
        }

        private void x4TexelCompressedTextureToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CreateTexture(5);
        }

        private void a5I3TranslucentTexture5bitAlpha3bitColorIndexToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CreateTexture(6);
        }

        private void directColorTextureToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CreateTexture(7);
        }

        private void toolStripMenuItem1_Click(object sender, EventArgs e)
        {
            CreateTexture(5, 512);
        }

        private void toolStripMenuItem3_Click(object sender, EventArgs e)
        {
            CreateTexture(5, 1024);
        }

        private void toolStripMenuItem4_Click(object sender, EventArgs e)
        {
            CreateTexture(5, 2048);
        }
    }
}
